/**
 * @file bull_hal_drv_led.c
 * @brief 
 * @author yejing (yejh@gongniu.cn)
 * @version 1.0
 * @date 2024-07-08
 * 
 * Copyright 2024-2025 GongNiu Inc. All Rights Reserved.
 * 
 */


#include "driver/ledc.h"
#include "bull_hal_drv_led.h"


#define BULL_LEDC_MAXT_CH           (6)
#define BULL_LEDC_LS_TIMER          LEDC_TIMER_1
#define BULL_LEDC_LS_MODE           LEDC_LOW_SPEED_MODE
#define BULL_LEDC_RESOLUTION        LEDC_TIMER_10_BIT           //PWM分辨率(10位)
#define BULL_DUTY_VAL_GET(x)        ((uint32_t)(10.24f * x))    //将占空比转换成分辨率相应的计数值

typedef struct{

    uint8_t is_used;
    ledc_channel_config_t config;
}ledc_channel_info_t;

static  ledc_channel_info_t ledc_info[BULL_LEDC_MAXT_CH] = { 0 };

/**
 * @brief LEDC控制模块初始化
 * 
 * @param gpio_num  PWM输出引脚
 * @param frequence PWM输出频率，取值范围是0-10K
 * @param polarity  PWM输出极性，1为高电平有效，0为低电平有效
 * @param duty      PWM初始占空比
 * @return int PWM通道编号，失败返回值小于0
 */
int bull_hal_drv_led_pwm_init( int gpio_num, int frequence, int polarity ,float duty )
{
    int chn_num;

    for( chn_num = 0; chn_num < BULL_LEDC_MAXT_CH; chn_num++) {
        if(ledc_info[chn_num].is_used == 0) {
            break;
        }
    }

    if( chn_num >= BULL_LEDC_MAXT_CH) {
        return -1;
    }

    if( frequence >= 10000 ) {
        return -2;
    }
    
    //配置LEDC定时器，配置多个PWM通道时仅初始化一次
    static bool is_timer_uninit = true;

    if( is_timer_uninit ) {

        ledc_timer_config_t ledc_timer = {
            .duty_resolution = BULL_LEDC_RESOLUTION,    // PWM分辨率/精度
            .freq_hz = frequence,                       // PWM输出频率
            .speed_mode = BULL_LEDC_LS_MODE,            // 定时器模式
            .timer_num = BULL_LEDC_LS_TIMER,            // 定时器编号
            .clk_cfg = LEDC_AUTO_CLK,                   // 选择时钟源
        };

        ledc_timer_config(&ledc_timer);
        is_timer_uninit = false;
    }

    //PWM通道配置
    ledc_info[chn_num].is_used = 1;
    ledc_info[chn_num].config.channel    = chn_num;                 //PWM通道编号
    ledc_info[chn_num].config.gpio_num   = gpio_num,                //PWM输出引脚
    ledc_info[chn_num].config.speed_mode = BULL_LEDC_LS_MODE;       //ESP32-S3只支持LEDC_LOW_SPEED_MODE
    ledc_info[chn_num].config.timer_sel  = BULL_LEDC_LS_TIMER;      //与配置LEDC定时器编号一致
    ledc_info[chn_num].config.duty       = BULL_DUTY_VAL_GET(duty); //初始占空比
    ledc_info[chn_num].config.hpoint     = 0;                       //通常不需要手动设置，根据duty自动计算
    ledc_info[chn_num].config.flags.output_invert = polarity?0:1;   //设置输出相位
    ledc_channel_config(&ledc_info[chn_num].config);

    return chn_num;
}

/**
 * @brief led控制的pwm占空比设置
 * 
 * @param channel_num   PWM通道编号
 * @param duty          占空比0~100
 */
void bull_hal_drv_led_pwm_duty_set( int pin_num, float duty )
{
    if( duty < 0) {
        duty = 0;
    }

    if( duty > 100 ){
        duty = 100;
    }
        
    for( uint8_t i=0; i < BULL_LEDC_MAXT_CH; i++) {

        if(ledc_info[i].config.gpio_num == pin_num) {

            ledc_set_duty( ledc_info[i].config.speed_mode, i, BULL_DUTY_VAL_GET(duty) );
            ledc_update_duty( ledc_info[i].config.speed_mode, i );
        }
    }
}

/**
 * @brief 失能 led pwm功能
 * 
 */
void  bull_hal_drv_led_pwm_uninstall( void )
{
    ledc_fade_func_uninstall();
}

